package com.bocomm.tracevisualization.core;

import com.bocomm.tracevisualization.api.entity.Traceroute;
import com.bocomm.tracevisualization.api.entity.TracerouteHop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
public class CmdExecutor {
    static final Pattern compile = Pattern.compile("[<>\\d]\\d*");
    public static void execTrace(int maxTTL, int packageNum, String remoteIp, Integer timeout, Traceroute traceroute  ) throws IOException, InterruptedException {

        if (remoteIp.isEmpty()) {
            return ; // 参数不能为空
        }
        traceroute.setSourceIp(fetchLocalHostIp());
        traceroute.setTargetIp(remoteIp);
        String line = "";
        long startTime;
        long endTime;
        if (System.getProperty("os.name").startsWith("Windows")) {

            String command = "tracert -4  %s";
            command = String.format(command, remoteIp);
            ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", command);
            traceroute.setCommandLine(command);
            startTime = System.currentTimeMillis();
            Process process = pb.start();
            try( BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));){

                process.waitFor(timeout ,TimeUnit.SECONDS);

                postProcess(reader,line,remoteIp, traceroute);
                traceroute.setSuccess(true);

            }



        } else { // 对于类Unix系统
            String commandShell = "traceroute -m %d  -q %d  -nI %s";
            commandShell = String.format(commandShell,maxTTL,packageNum,remoteIp);
            ProcessBuilder pb = new ProcessBuilder("bash", "-c", commandShell);
            traceroute.setCommandLine(commandShell);
            startTime = System.currentTimeMillis();
            Process process = pb.start();

            try(BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.defaultCharset()));) {
                // 等待进程结束
                process.waitFor(timeout, TimeUnit.SECONDS);

                // 同样读取输出并处理...
                postProcess(reader, line, remoteIp, traceroute);

                traceroute.setSuccess(true);
            }

        }
        endTime = System.currentTimeMillis();

        traceroute.setCommandCost((endTime - startTime)/1000);
    }

    /**
     * 该函数通过读取BufferedReader中的每一行文本，对每一行进行分析处理，并将处理结果添加到tracerouteHops列表中，最后返回该列表。其中，analysis方法对每一行文本进行分析，返回一个TracerouteHop对象。
     *
     * @param reader
     * @param line
     * @param targetIp 目标Ip
     * @param linux
     * @return
     * @throws IOException
     */
    public static void postProcess(BufferedReader reader, String line, String targetIp, Traceroute linux) throws IOException {
        List<TracerouteHop> tracerouteHops = linux.getTracerouteHops();
        while ((line = reader.readLine()) != null) {
            TracerouteHop hopLine = analysis(line);
            if(hopLine.getHopNumber() == 0){
                continue;
            }
            //package获取ms数的最后一个
            List<TracerouteHop.TracePackages> tracePackages = hopLine.getTracePackages();
            for (TracerouteHop.TracePackages tracePackage : tracePackages) {
                double rrtTime = 0.0d;
                List<Double> rttTimes = tracePackage.getRttTimes();
                if (!CollectionUtils.isEmpty(rttTimes)) {
                    for (int i = rttTimes.size()-1; i >=0; i--) {
                        if(rttTimes.get(i) != null && rttTimes.get(i)!= 0.0d){
                            rrtTime= rttTimes.get(i);
                        }
                    }
                }
                hopLine.setLastTrtTime(rrtTime);

            }
            hopLine.setSourceLine(line);
            if ("*".equals(hopLine.getLastTargetIp())) {
                hopLine.setConnected(false);
                tracerouteHops.add(hopLine);
            }else if(StringUtils.hasText(hopLine.getLastTargetIp())){
                hopLine.setConnected(true);
            }
            tracerouteHops.add(hopLine);
        }
    }

    /**
     * 对每一行文本进行分析，返回一个TracerouteHop对象。
     * @param line
     * @return
     */
    public static TracerouteHop analysis(String line) {
        String trim = line.trim();
        TracerouteHop tracerouteHops = new TracerouteHop();
        if (!StringUtils.hasText(trim)) {
            return tracerouteHops;
        }

        List<TracerouteHop.TracePackages> tracePackages = tracerouteHops.getTracePackages();
        TracerouteHop.TracePackages tracerouteTracePackages = new TracerouteHop.TracePackages();
        String[] s = trim.split("[ ]+");
        boolean flag = true;
        for (int i = 0; i < s.length; i++) {
            if(0 == i) {

                String s1 = s[i];
                Matcher matches = compile.matcher(s1);
                if(matches.matches()) {
                    tracerouteHops.setHopNumber(Integer.parseInt(s1));
                    flag = false;
                }
                continue;
            }
            if(flag){
                break;
            }
            String s1 = s[i];
            if("*".equals(s1.trim())){
                tracePackages.add(tracerouteTracePackages);
                tracerouteTracePackages = new TracerouteHop.TracePackages();
                continue;
            }
            if (checkIpAddress(s1)) {
                tracePackages.add(tracerouteTracePackages);
                tracerouteHops.setLastTargetIp(s1);
                continue;
            }
            String s2 = s1.replaceAll("[()\\[\\]]", "");
            if (checkIpAddress(s2)) {
                tracerouteHops.setLastTargetIp(s2);
                continue;

            }
            if (!StringUtils.hasText(s1)|| org.apache.commons.lang3.StringUtils.equalsAny(s1,"ms","毫秒","s")) {
                continue;
            }

            checkRttTimes(s, i, tracerouteTracePackages);
            tracePackages.add(tracerouteTracePackages);
            tracerouteTracePackages = new TracerouteHop.TracePackages();

        }

        return tracerouteHops;
    }

    /**
     * 检查rtt时间
     * @param s
     * @param i
     * @param tracerouteTracePackages
     * @return
     */
    private static boolean checkRttTimes(String[] s, int i, TracerouteHop.TracePackages tracerouteTracePackages) {
        String s1 = s[i];
        String s2 = (s.length-1 >= (i+1)) ? s[i+1] : "";
        if(!StringUtils.hasText(s2)){
            return false;
        }
        List<Double> rttTimes = tracerouteTracePackages.getRttTimes();
        if(null == rttTimes){
            rttTimes = new ArrayList<>();
            tracerouteTracePackages.setRttTimes(rttTimes);
        }
        double v = 0.0d;
        if ("ms".equals(s2)){
            if(s1.contains("<")){
              s1= s1.replace("<","");
            }
            try {
                v = Double.parseDouble(s1);
            }catch (Exception ignored){
            }

            rttTimes.add(v);
            return true;
        }


        return false;
    }

    /**
     * 匹配IP地址(简单匹配，格式，如：192.168.1.1，127.0.0.1，没有匹配IP段的大小)
     * @param ipAddress IPv4标准地址
     * @return 验证成功返回true，验证失败返回false
     */
    public static boolean checkIpAddress(String ipAddress) {
        String regex = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
        return Pattern.matches(regex, ipAddress);
    }

    public static String fetchLocalHostIp(){
        String ipv4 = "";
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                if (!networkInterface.isLoopback() && networkInterface.isUp()) {
                    Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                    while (inetAddresses.hasMoreElements()) {
                        InetAddress inetAddress = inetAddresses.nextElement();
                        if (inetAddress instanceof Inet4Address) { // 如果你只需要IPv4地址
                            ipv4 = inetAddress.getHostAddress();
                            break; // 如果找到一个就跳出循环（如果你需要所有IP则不需要break）
                        }
                    }
                }
            }
        } catch (SocketException e) {

            log.error("无法获取网络接口信息");
        }
        return ipv4;
    }


}